package com.oauthorization.server.config.redis;

import com.oauthorization.server.config.content.SupplierDeferredSecurityContext;
import com.oauthorization.server.contants.RedisConstants;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.DeferredSecurityContext;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;


/**
 * 基于redis存储认证信息
 */
@Component
@RequiredArgsConstructor
public class RedisSecurityContextRepository implements SecurityContextRepository {

    private final RedisTemplate<String,SecurityContext> securityContextRedisTemplate;

    private final SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();

    @Override
    public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
//        HttpServletRequest request = requestResponseHolder.getRequest();
//        String sessionId = request.getSession().getId();
//        SecurityContext context = securityContextRedisTemplate.getValue(sessionId);
//        return context != null ? context : SecurityContextHolder.createEmptyContext();
        throw new UnsupportedOperationException("Method deprecated.");
    }

    @Override
    public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
        String sessionId = request.getSession().getId();
        if (ObjectUtils.isEmpty(sessionId)) {
            return;
        }
        // 如果当前的context是空的，则移除
        SecurityContext emptyContext = this.securityContextHolderStrategy.createEmptyContext();
        if (emptyContext.equals(context)) {
            securityContextRedisTemplate.delete((RedisConstants.SECURITY_CONTEXT_PREFIX_KEY + sessionId));
        } else {
            // 保存认证信息
            securityContextRedisTemplate.opsForValue().set((RedisConstants.SECURITY_CONTEXT_PREFIX_KEY + sessionId), context, 30, TimeUnit.MINUTES);
        }

    }

    @Override
    public boolean containsContext(HttpServletRequest request) {
        String sessionId = request.getSession().getId();
        return securityContextRedisTemplate.hasKey(RedisConstants.SECURITY_CONTEXT_PREFIX_KEY + sessionId);
    }

    @Override
    public DeferredSecurityContext loadDeferredContext(HttpServletRequest request) {
        String sessionId = request.getSession().getId();
        Supplier<SecurityContext> supplier = () -> securityContextRedisTemplate.opsForValue().get(RedisConstants.SECURITY_CONTEXT_PREFIX_KEY + sessionId);
        return new SupplierDeferredSecurityContext(supplier, this.securityContextHolderStrategy);
    }

    public void clearContext(HttpServletRequest request) {
        String sessionId = request.getRequestedSessionId();
        securityContextRedisTemplate.delete(RedisConstants.SECURITY_CONTEXT_PREFIX_KEY + sessionId);
    }


//    @Override
//    public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
////        HttpServletRequest request = requestResponseHolder.getRequest();
////        return readSecurityContextFromRedis(request);
//        // 方法已过时，使用 loadDeferredContext 方法
//        throw new UnsupportedOperationException("Method deprecated.");
//    }
//
//    @Override
//    public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
//        String nonce = getNonce(request);
//        if (ObjectUtils.isEmpty(nonce)) {
//            return;
//        }
//
//        // 如果当前的context是空的，则移除
//        SecurityContext emptyContext = this.securityContextHolderStrategy.createEmptyContext();
//        if (emptyContext.equals(context)) {
//            securityContextRedisTemplate.delete((RedisConstants.SECURITY_CONTEXT_PREFIX_KEY + nonce));
//        } else {
//            // 保存认证信息
//            securityContextRedisTemplate.setValue((RedisConstants.SECURITY_CONTEXT_PREFIX_KEY + nonce), context, RedisConstants.DEFAULT_TIMEOUT_SECONDS);
//        }
//    }
//
//    @Override
//    public boolean containsContext(HttpServletRequest request) {
//        String nonce = getNonce(request);
//        if (ObjectUtils.isEmpty(nonce)) {
//            return false;
//        }
//        // 检验当前请求是否有认证信息
//        return securityContextRedisTemplate.getValue((RedisConstants.SECURITY_CONTEXT_PREFIX_KEY + nonce)) != null;
//    }
//
//    @Override
//    public DeferredSecurityContext loadDeferredContext(HttpServletRequest request) {
//        Supplier<SecurityContext> supplier = () -> readSecurityContextFromRedis(request);
//        return new SupplierDeferredSecurityContext(supplier, this.securityContextHolderStrategy);
//    }
//
//    /**
//     * 从redis中获取认证信息
//     *
//     * @param request 当前请求
//     * @return 认证信息
//     */
//    private SecurityContext readSecurityContextFromRedis(HttpServletRequest request) {
//        if (request == null) {
//            return null;
//        }
//
//        String nonce = getNonce(request);
//        if (ObjectUtils.isEmpty(nonce)) {
//            return null;
//        }
//        System.out.println(securityContextRedisTemplate.getValue((RedisConstants.SECURITY_CONTEXT_PREFIX_KEY + nonce)));
//        // 根据缓存id获取认证信息
//        return securityContextRedisTemplate.getValue((RedisConstants.SECURITY_CONTEXT_PREFIX_KEY + nonce));
//    }
//
//    /**
//     * 先从请求头中找，找不到去请求参数中找，找不到获取当前session的id
//     * 新增逻辑：获取当前session的sessionId
//     *
//     * @param request 当前请求
//     * @return 随机字符串(sessionId)，这个字符串本来是前端生成，现在改为后端获取的sessionId
//     */
//    private String getNonce(HttpServletRequest request) {
//        String nonce = request.getHeader(SecurityConstants.NONCE_HEADER_NAME);
//        if (ObjectUtils.isEmpty(nonce)) {
//            nonce = request.getParameter(SecurityConstants.NONCE_HEADER_NAME);
//            HttpSession session = request.getSession(Boolean.FALSE);
//            if (ObjectUtils.isEmpty(nonce) && session != null) {
//                nonce = session.getId();
//            }
//        }
//        return nonce;
//    }

}
